/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package dropclient;

import com.progin.drop.core.Message;
import com.progin.drop.core.MessageException;
import com.progin.drop.core.MessageOperator;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.rmi.CORBA.Util;

/**
 *
 * @author Pudy
 */
public class MessageComm {
    private Socket mSock;
    private ArrayList<FileDescription> mServerFiles;
    private ArrayList<FileDescription> mClientFiles;
    private ArrayList<FileDescription> mUploadedFiles;
    private ArrayList<FileDescription> mDownloadedFiles;
    private ArrayList<FileDescription> mDeletedFiles = new ArrayList<FileDescription>();

    public MessageComm() {
    }

    public MessageComm(Socket sock) {
        mServerFiles = new ArrayList<FileDescription>();
        mSock = sock;
    }

    public void synchronize() {
        
        new Thread(new Runnable() {
            public void run() {
                System.out.println("TIMED SYNC");
                getServerFiles();
                getClientFiles();
                getDeletedFiles();
                DropClientApp.getApplication().setCurrentFiles(mClientFiles);
                compareFilesClientServer();


                try {
                    uploadFiles();
                    downloadFiles();
                    deleteFiles();
                } catch (UnknownHostException ex) {
                    Logger.getLogger(MessageComm.class.getName()).log(Level.SEVERE, null, ex);
                } catch (IOException ex) {
                    Logger.getLogger(MessageComm.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }).start();
    }

    private void getServerFiles(){
        Message m = new Message(Message.MESSAGE_LIST_FILES , null);
        m.getmHeaders().add(DropClientApp.getApplication().user_id);
        MessageOperator mo = new MessageOperator(m);
        try {
            mo.send(mSock);
            m = mo.receive(mSock);
            System.out.println(m);
            parseMessage(m);
        } catch (MessageException ex) {
            Logger.getLogger(MessageComm.class.getName()).log(Level.SEVERE, ex.getMessage(), ex);
        }
    }

    private void parseMessage(Message msg) {
        for (String s : msg.getmBodies()) {
            mServerFiles.add(new FileDescription(s));
        }
    }

    private void getDeletedFiles() {
        mDeletedFiles = new ArrayList<FileDescription>();
        String path = DropClientApp.getApplication().curpath;
        File dir = new File(path);
        File[] files = dir.listFiles();
        for (FileDescription fd : DropClientApp.getApplication().getCurrentFiles()) {
            boolean found = false;
            for (File f : files) {
                if (f.isFile()) {
                    if (f.getName().equals(fd.getFilename())) {
                        found = true;
                    }
                }
            }
            if (!found) {
                mDeletedFiles.add(fd);
                fd.setDeleted(true);
                System.out.println("DELETED : " + fd.getFilename());
            }
        }
    }

    private void getClientFiles(){
        String path = DropClientApp.getApplication().curpath;
        //String path = "E:/Glee/Glee Season 2/";
        FileDescription fd;
        mClientFiles = new ArrayList<FileDescription>();
        
        File dir = new File(path);
        File[] files = dir.listFiles();
        for (File f : files) {
            if (f.isFile()) {
                fd = new FileDescription(f);
                mClientFiles.add(fd);
            }
        }
    }

    private void compareFilesClientServer(){
        boolean found;
        int j;
        mDownloadedFiles = new ArrayList<FileDescription>();
        mUploadedFiles = new ArrayList<FileDescription>();

        for (int i=0; i<mServerFiles.size(); ++i){
            if (!mServerFiles.get(i).getIsDeleted()) {
                found = false;
                j = 0;
                while (!found && j!=mClientFiles.size()) {
                    if (mServerFiles.get(i).getFilename().equals(mClientFiles.get(j).getFilename())) {
                        found = true;
                    } else {
                        ++j;
                    }
                }
                if (found) {
                    //compare date modified
                    if (mServerFiles.get(i).getIsDeleted()) {
                        File f = new File(DropClientApp.getApplication().curpath + "/" + mServerFiles.get(i).getFilename());
                        if (f.exists()) {
                            f.renameTo(new File(f.getAbsolutePath() + ".del"));
                        }
                    }
                    else {
                        int comp = Long.valueOf(mServerFiles.get(i).getDatemodified()).compareTo(Long.valueOf(mClientFiles.get(j).getDatemodified()));
                        if (comp < 0) {
                            //kalo newer di client, add file ke mUploadedFiles, delete file di server
                            mUploadedFiles.add(mClientFiles.get(j));
                            //mServerFiles.remove(i);
                        } else if (comp > 0) {
                            //kalo newer di server, add file ke mDownloadedFiles, delete file di client
                            mDownloadedFiles.add(mServerFiles.get(i));
                            //mClientFiles.remove(j);
                        }
                    }
                } else {
                    mDownloadedFiles.add(mServerFiles.get(i));
                }
            }
        }

        for (FileDescription fd : mServerFiles) {
            System.out.print(fd.getFilename() + " ");
        }
        System.out.println("");
        for (FileDescription fd : mClientFiles) {
            System.out.print(fd.getFilename() + " ");
        }
        System.out.println("");

        for (int i=0; i<mClientFiles.size(); ++i){
            found = false;
            j = 0;
            while (!found && j!=mServerFiles.size()) {
                if (mClientFiles.get(i).getFilename().equals(mServerFiles.get(j).getFilename())) {
                    found = true;
                } else {
                    ++j;
                }
            }
            if (found) {
                //System.out.println("FOUND " + i + " " + j);
            } else {
                mUploadedFiles.add(mClientFiles.get(i));
            }
        }
    }
    
    private void uploadFiles() throws UnknownHostException, IOException{
        MessageOperator mo = new MessageOperator();
        for (FileDescription fd : mUploadedFiles) {
            mSock = new Socket(DropClientApp.getApplication().serverAddress , 2000);
            try {
                Message m = new Message(Message.MESSAGE_SEND_FILE , new File(DropClientApp.getApplication().curpath + "/" + fd.getFilename()));
                m.getmHeaders().add(DropClientApp.getApplication().user_id);
                m.getmBodies().add(fd.getFilename());
                //m.setByteStream(readFile(new File(DropClientApp.getApplication().curpath + "/" + fd.getFilename())));

                mo.setTargetMessage(m);
                mo.send(mSock);
                
                //m = mo.receive(mSock);

                System.out.println("Upload : " + m);
            } catch (MessageException ex) {
                Logger.getLogger(MessageComm.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
    
    private void downloadFiles() throws UnknownHostException, IOException{
        MessageOperator mo = new MessageOperator();
        for (FileDescription fd : mDownloadedFiles) {
            mSock = new Socket(DropClientApp.getApplication().serverAddress , 2000);

            boolean skipped = false;
            /*for (FileDescription fd2 : mDeletedFiles) {
                if (fd.getFilename().equals(fd2.getFilename()))
                    skipped = true;
            }*/
            if (!skipped) {
                try {
                    Message m = new Message(Message.MESSAGE_REQUEST_FILE , null);
                    m.getmHeaders().add(DropClientApp.getApplication().user_id);
                    m.getmBodies().add(fd.getFilename());
                    mo.setTargetMessage(m);
                    System.out.println("Download : " + m);
                    mo.send(mSock);
                    m = mo.receive(mSock);

                    //System.out.println("Download : " + m);
                    if (m.getmHeaders().get(2).equals("0")) {
                        writeFile(m.getBody(0), m.getByteStream());
                    }
                } catch (MessageException ex) {
                    Logger.getLogger(MessageComm.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    }

    private void deleteFiles() throws UnknownHostException, IOException {
        MessageOperator mo = new MessageOperator();
        for (FileDescription fd : mDeletedFiles) {
            mSock = new Socket(DropClientApp.getApplication().serverAddress , 2000);
            try {
                Message m = new Message(Message.MESSAGE_REQUEST_FILE , null);
                m.getmHeaders().add(DropClientApp.getApplication().user_id);
                m.getmBodies().add(fd.getFilename());
                m.getmBodies().add("delete");
                mo.setTargetMessage(m);
                mo.send(mSock);
                System.out.println("Delete : " + m);

                m = mo.receive(mSock);
                System.out.println("Delete 2 : " + m);
            } catch (MessageException ex) {
                Logger.getLogger(MessageComm.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    private void writeFile(String filename , byte[] stream) {
        try {
            File targetFile = new File(DropClientApp.getApplication().curpath + "/" + filename);
            FileOutputStream out;

            if (targetFile.createNewFile()) {
            }
            else {
            }

            if (stream != null) {
                out = new FileOutputStream(targetFile);
                out.write(stream);
                out.close();
            }

        } catch (IOException ex) {
            Logger.getLogger(Handler.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private byte[] readFile(File file) {
        if (file.exists() && file.isFile()) {
            FileInputStream fis;
            try {
                fis = new FileInputStream(file);
                byte[] b = new byte[(int)file.length()];
                fis.read(b);
                fis.close();

                return b;
            } catch (IOException ex) {
                Logger.getLogger(Util.class.getName()).log(Level.SEVERE, null, ex);
                return null;
            }
        }
        else
            return null;
    }

    public static void main(String[] args) {
        MessageComm comm = new MessageComm();
        comm.getClientFiles();
    }
}
